#include "AABBox.h"
#include <trax.hpp>

namespace AtomTrace
{
    AABBox::AABBox()
    {
        pmin[0]=10000.0f;
        pmin[1]=10000.0f;
        pmin[2]=10000.0f;

        pmax[0]=-10000.0f;
        pmax[1]=-10000.0f;
        pmax[2]=-10000.0f;
    }

    AABBox::AABBox(const Vector3 & iMin, const Vector3 & iMax)
    {
        pmin[0] = iMin[0];
        pmin[1] = iMin[1];
        pmin[2] = iMin[2];

        pmax[0] = iMax[0];
        pmax[1] = iMax[1];
        pmax[2] = iMax[2];
    }

    AABBox::AABBox(float minX, float minY, float minZ,
            float maxX, float maxY, float maxZ)
    {
        pmin[0] = minX;
        pmin[1] = minY;
        pmin[2] = minZ ;

        pmax[0] = maxX;
        pmax[1] = maxY;
        pmax[2] = maxZ;
    }

    bool AABBox::IsEmpty() const
    {
        for(int i=0; i<3; i++)
        {
            if(pmin[i] >= pmax[i])
            {
                return true;
            }
        }

        return false;
    }

    bool AABBox::Intersect(const Ray & ray, float & t_max) const
    {
        if(IsEmpty()) return false;
        const float eps = 0.001f;

        float t1[3];
        float t2[3];

        // only consider ray origin outside the box
        for(int i=0; i<3; i++)
        {
            if(ray._dir[i] < eps && ray._dir[i] > -eps)
            {
                if(ray._o[i] < pmin[i] || ray._o[i] > pmax[i])
                    return false;
                else{
                    t1[i] = -1000000.0f; // negative infinity
                    t2[i] =  1000000.0f; // positive infinity
                    continue;
                }
            }
            t1[i] = (pmin[i] - ray._o[i])/ ray._dir[i];
            t2[i] = (pmax[i] - ray._o[i])/ ray._dir[i];

            if(t1[i] > t2[i])
            {
                float temp = t1[i];
                t1[i] = t2[i];
                t2[i] = temp;
            }

        }

        float tEnter = max(t1[0], t1[1]); tEnter = max(tEnter, t1[2]);
        float tExit = min(t2[0], t2[1]); tExit = min(tExit, t2[2]);

        //if(tmin < 0.0f) tmin = 0.0f;

        if(tEnter > tExit) return false;

        float tres;

        if(tEnter >= 0.0f)
        {
            tres = tEnter;
        }else
            tres = tExit;

        if(tres < t_max ) // z depth test
        {
            t_max = tres;
            return true;
        }
        
        return false;
    }
}
